package com.xiaobai.excel.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaobai.excel.entity.ExcelConfig;
import com.xiaobai.excel.entity.ExcelConfigField;
import com.xiaobai.excel.entity.ExcelConfigPro;
import com.xiaobai.excel.handler.CellRowHeightStyleStrategy;
import com.xiaobai.excel.handler.CellStyleStrategy;
import com.xiaobai.excel.handler.CellWidthStyleStrategy;
import com.xiaobai.excel.mapper.ExcelConfigFieldMapper;
import com.xiaobai.excel.mapper.ExcelConfigMapper;
import com.xiaobai.excel.mapper.ExcelConfigProMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ExcelUtil {
    @Resource
    ExcelConfigProMapper excelConfigSqlMapper;
    @Resource
    private ExcelConfigMapper excelConfigMapper;
    @Resource
    private ExcelConfigFieldMapper excelConfigFieldMapper;

    public void exportExcel(HttpServletResponse response, String module, Map<String, String> paramMap) throws IOException {
        final Result result = getResult(module, null, paramMap);
        writeResponse(response, result);
    }

    public void exportExcel(String file, String module, List<Map<String, Object>> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            throw new RuntimeException("data list is null !");
        }
        final Result result = getResult(module, dataList, null);
        writeFile(file, result);
    }

    public void exportExcel(String file, String module, Map<String, String> paramMap) {
        final Result result = getResult(module, null, paramMap);
        writeFile(file, result);
    }

    private Result getResult(String module, List<Map<String, Object>> mapList, Map<String, String> paramMap) {
        ExcelConfig excelConfig = excelConfigMapper.selectOne(new LambdaQueryWrapper<ExcelConfig>()
                .eq(ExcelConfig::getModule, module));

        Objects.requireNonNull(excelConfig, "module is not exist !");
        final ExcelConfigPro excelConfigPro = excelConfigSqlMapper.selectOne(new LambdaQueryWrapper<ExcelConfigPro>()
                .eq(ExcelConfigPro::getConfigId, excelConfig.getId()));
        Objects.requireNonNull(excelConfig, "module's field config is not exist !");
        if (CollectionUtils.isEmpty(mapList)) {
            // TODO 这里看看如何组装查询语句
            final StringBuilder sql = new StringBuilder(excelConfigPro.getDetailSql());
            sql.append(" where 1=1");
            paramMap.forEach((key, value) -> {
                sql.append(" and ").append(key).append("=").append(value);
            });
            mapList = excelConfigSqlMapper.executeSQL(sql.toString());
        }


        final List<ExcelConfigField> configFieldList = excelConfigFieldMapper.selectList(new LambdaQueryWrapper<ExcelConfigField>()
                .eq(ExcelConfigField::getConfigId, excelConfig.getId())
                .orderByAsc(ExcelConfigField::getOrderNum)
                .eq(ExcelConfigField::getDelFlag, 0)
                .eq(ExcelConfigField::getStatus, 0));

        final List<List<String>> headList = configFieldList.stream().map(v -> {
            List<String> list = new ArrayList<>();
            list.add(v.getTitle());
            return list;
        }).collect(Collectors.toList());

        final List<List<String>> headFieldList = configFieldList.stream().map(v -> {
            List<String> list = new ArrayList<>();
            list.add(v.getField());
            return list;
        }).collect(Collectors.toList());

        final List<Short> headBackColor = configFieldList.stream().map(ExcelConfigField::getHeadBackColor).collect(Collectors.toList());
        final List<Short> contentBackColor = configFieldList.stream().map(ExcelConfigField::getContentBackColor).collect(Collectors.toList());


        final List<Short> headFontColor = configFieldList.stream().map(ExcelConfigField::getHeadFontColor).collect(Collectors.toList());
        final List<Short> contentFontColor = configFieldList.stream().map(ExcelConfigField::getContentFontColor).collect(Collectors.toList());

        final List<Short> headFontSize = configFieldList.stream().map(ExcelConfigField::getHeadFontSize).collect(Collectors.toList());
        final List<Short> contentFontSize = configFieldList.stream().map(ExcelConfigField::getContentFontSize).collect(Collectors.toList());


        final List<Boolean> headFontBold = configFieldList.stream().map(ExcelConfigField::getHeadFontBold).collect(Collectors.toList());
        final List<Boolean> contentFontBold = configFieldList.stream().map(ExcelConfigField::getContentFontBold).collect(Collectors.toList());

        Map<Integer, Integer> widthMap = new LinkedHashMap<>();

        for (int i = 0; i < configFieldList.size(); i++) {
            widthMap.put(i, configFieldList.get(i).getWidth());
        }

        List<List<Object>> contentList = mapList.stream().map(fileContent -> {
            List<Object> rowList = new ArrayList<>();
            for (List<String> strings : headFieldList) {
                Object content = fileContent.get(strings.get(0));
                rowList.add(content == null ? "" : content);
            }
            return rowList;
        }).collect(Collectors.toList());
        return new Result(excelConfig, excelConfigPro, headList, headBackColor, contentBackColor, headFontColor, contentFontColor, headFontSize, contentFontSize, headFontBold, contentFontBold, widthMap, contentList);
    }


    private void writeResponse(HttpServletResponse response, Result result) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode(result.excelConfig.getDescription(), "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream()).sheet(result.excelConfigPro.getSheetName())
                .registerWriteHandler(new CellRowHeightStyleStrategy(result.excelConfigPro.getHeadHeight(), result.excelConfigPro.getContentHeight()))   //设置行高的策略
                .registerWriteHandler(new CellStyleStrategy(new WriteCellStyle(),
                        new WriteCellStyle(),
                        result.excelConfigPro.getHeadBackColor(),
                        result.excelConfigPro.getContentBackColor(),
                        result.headBackColor,
                        result.contentBackColor,
                        result.excelConfigPro.getHeadFontColor(),
                        result.excelConfigPro.getContentFontColor(),
                        result.headFontColor,
                        result.contentFontColor,
                        result.excelConfigPro.getHeadFontSize(),
                        result.excelConfigPro.getContentFontSize(),
                        result.headFontSize,
                        result.contentFontSize,
                        result.excelConfigPro.getHeadFontBold(),
                        result.excelConfigPro.getContentFontBold(),
                        result.headFontBold,
                        result.contentFontBold))
                .registerWriteHandler(new CellWidthStyleStrategy(result.widthMap))
                .head(result.headList).doWrite(result.contentList);
    }

    private void writeFile(String file, Result result) {
        EasyExcel.write(file).sheet(result.excelConfigPro.getSheetName())
                .registerWriteHandler(new CellRowHeightStyleStrategy(result.excelConfigPro.getHeadHeight(), result.excelConfigPro.getContentHeight()))   //设置行高的策略
                .registerWriteHandler(new CellStyleStrategy(new WriteCellStyle(),
                        new WriteCellStyle(),
                        result.excelConfigPro.getHeadBackColor(),
                        result.excelConfigPro.getContentBackColor(),
                        result.headBackColor,
                        result.contentBackColor,
                        result.excelConfigPro.getHeadFontColor(),
                        result.excelConfigPro.getContentFontColor(),
                        result.headFontColor,
                        result.contentFontColor,
                        result.excelConfigPro.getHeadFontSize(),
                        result.excelConfigPro.getContentFontSize(),
                        result.headFontSize,
                        result.contentFontSize,
                        result.excelConfigPro.getHeadFontBold(),
                        result.excelConfigPro.getContentFontBold(),
                        result.headFontBold,
                        result.contentFontBold))
                .registerWriteHandler(new CellWidthStyleStrategy(result.widthMap))
                .head(result.headList).doWrite(result.contentList);
    }

    private static class Result {
        public final ExcelConfig excelConfig;
        public final ExcelConfigPro excelConfigPro;
        public final List<List<String>> headList;
        public final List<Short> headBackColor;
        public final List<Short> contentBackColor;
        public final List<Short> headFontColor;
        public final List<Short> contentFontColor;
        public final List<Short> headFontSize;
        public final List<Short> contentFontSize;
        public final List<Boolean> headFontBold;
        public final List<Boolean> contentFontBold;
        public final Map<Integer, Integer> widthMap;
        public final List<List<Object>> contentList;

        public Result(ExcelConfig excelConfig, ExcelConfigPro excelConfigPro, List<List<String>> headList, List<Short> headBackColor, List<Short> contentBackColor, List<Short> headFontColor, List<Short> contentFontColor, List<Short> headFontSize, List<Short> contentFontSize, List<Boolean> headFontBold, List<Boolean> contentFontBold, Map<Integer, Integer> widthMap, List<List<Object>> contentList) {
            this.excelConfig = excelConfig;
            this.excelConfigPro = excelConfigPro;
            this.headList = headList;
            this.headBackColor = headBackColor;
            this.contentBackColor = contentBackColor;
            this.headFontColor = headFontColor;
            this.contentFontColor = contentFontColor;
            this.headFontSize = headFontSize;
            this.contentFontSize = contentFontSize;
            this.headFontBold = headFontBold;
            this.contentFontBold = contentFontBold;
            this.widthMap = widthMap;
            this.contentList = contentList;
        }
    }
}
